﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml.Linq;
using VisualRibbonEditor;

namespace VisualRibbonEditor
{
	public partial class ButtonDetails : UserControl
	{
		private XElement _sourceElement;

		private bool _isEditable;

		public ButtonDetails()
		{
			InitializeComponent();
		}

		public ButtonDetails(XElement element)
		{
			InitializeComponent();
			this._sourceElement = element;

			this.IdTextBox.Text = GetAttributeValue(element, "Id");

			//disable editing for system buttons
			this._isEditable = Helpers.IsButtonEditable(GetAttributeValue(element, "Id"));
			
			// load languages
			foreach (string lang in MainWindow.CurrentSolution.ProvisionedLanguages)
			{
				int lcid;
				if (!Int32.TryParse(lang, out lcid)) continue;

				CultureInfo cultureInfo = CultureInfo.GetCultureInfo(lcid);
				string languageName = String.Format("[{0}] {1}{2}", lang, cultureInfo.NativeName, (lcid == 1033 ? String.Empty : " - " + cultureInfo.EnglishName));
				ComboBoxItem item = new ComboBoxItem() { Content = languageName, Tag = lang };
				LanguageId.Items.Add(item);
				if (_isEditable)
				{
					if (lang == Connection.CurrentConnection.LastLanguageUsed) LanguageId.SelectedItem = item;
					if (lang == Connection.CurrentConnection.BaseLanguage) item.FontWeight = FontWeights.Bold;
				}
				else
				{
					if (lang == Connection.CurrentConnection.BaseLanguage) LanguageId.SelectedItem = item;
				}
			}

			LoadLabel(element, "LabelText", LabelTextBox);
			LoadLabel(element, "ToolTipTitle", ToolTipTitleTextBox);
			LoadLabel(element, "ToolTipDescription", TooltipDescriptionTextBox);

			this.PositionTextBox.Text = GetAttributeValue(element, "Sequence");
			
			//button size....
			string templateAlias = GetAttributeValue(element, "TemplateAlias");
			if (_isEditable)
			{
				LoadAvailableSizes();
				this.SizePicker.SelectedValue = templateAlias;
			}
			else
			{
				//if not editable then we can just populate the current templateAlias to show it.
				this.SizePicker.Items.Add(templateAlias);
				this.SizePicker.SelectedItem = templateAlias;
			}

			this.Image16TextBox.Text = GetAttributeValue(element, "Image16by16");
			this.Image32TextBox.Text = GetAttributeValue(element, "Image32by32");

			
			if (!_isEditable)
			{
				//make the control read-only.
				this.ReadOnlyButtonWarining.Visibility = Visibility.Visible;
				this.LanguageId.IsReadOnly = true;
				this.LanguageId.IsEnabled = false;
				this.LabelTextBox.IsReadOnly = true;
				this.ToolTipTitleTextBox.IsReadOnly = true;
				this.TooltipDescriptionTextBox.IsReadOnly = true;
				this.PositionTextBox.IsReadOnly = true;
				this.MoveLeft.Visibility = Visibility.Collapsed;
				this.MoveRight.Visibility = Visibility.Collapsed;
				this.SizePicker.IsEnabled = false;

				//replace the autocomplete boxes with readonly textboxes (autocomplete boxes can't be made readonly)
				this.Image16TextBox.Visibility = Visibility.Collapsed;
				this.Image16TextBoxReadOnly.Visibility = Visibility.Visible;
				this.Image16TextBoxReadOnly.Text = this.Image16TextBox.Text;
				this.BrowseForImage16.Visibility = Visibility.Collapsed;
				this.Image32TextBox.Visibility = Visibility.Collapsed;
				this.Image32TextBoxReadOnly.Visibility = Visibility.Visible;
				this.Image32TextBoxReadOnly.Text = this.Image32TextBox.Text;
				this.BrowseForImage32.Visibility = Visibility.Collapsed;
			}
			else
			{
				//set up events
				this.SizePicker.SelectionChanged += new SelectionChangedEventHandler(SizePicker_SelectionChanged);

				WebResourceManager.SetupImageAutoComplete(new AutoCompleteBox[] { Image16TextBox, Image32TextBox });

				SetupEnterKeyHandler(LabelTextBox, LabelTextBox_LostFocus);
				SetupEnterKeyHandler(ToolTipTitleTextBox, ToolTipTitleTextBox_LostFocus);
				SetupEnterKeyHandler(TooltipDescriptionTextBox, TooltipDescriptionTextBox_LostFocus);
				SetupEnterKeyHandler(PositionTextBox, PositionTextBox_LostFocus);
				SetupEnterKeyHandler(Image16TextBox, Image16TextBox_LostFocus);
				SetupEnterKeyHandler(Image32TextBox, Image32TextBox_LostFocus);
			}
		}


		#region Labels

		private void LabelTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			if (_isEditable)
			{
				SaveLabel(LabelTextBox, new string[] { "LabelText" });
				LoadLabel(this._sourceElement, "ToolTipTitle", ToolTipTitleTextBox);
				LoadLabel(this._sourceElement, "ToolTipDescription", TooltipDescriptionTextBox);
			}
		}

		private void ToolTipTitleTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			if (_isEditable)
			{
				SaveLabel(ToolTipTitleTextBox, new string[] { "ToolTipTitle" });
				LoadLabel(this._sourceElement, "LabelText", LabelTextBox);
				LoadLabel(this._sourceElement, "ToolTipDescription", TooltipDescriptionTextBox);
			}
		}

		private void TooltipDescriptionTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			if (_isEditable)
			{
				SaveLabel(TooltipDescriptionTextBox, new string[] { "ToolTipDescription" });
				LoadLabel(this._sourceElement, "LabelText", LabelTextBox);
				LoadLabel(this._sourceElement, "ToolTipTitle", ToolTipTitleTextBox);
			}
		}

		private string GetSelectedLanguage()
		{
			if (LanguageId.SelectedItem == null) return Connection.CurrentConnection.BaseLanguage;

			ComboBoxItem lang = (ComboBoxItem)LanguageId.SelectedItem;
			return lang.Tag.ToString();
		}

		private void LoadLabel(XElement buttonElement, string attributeName, TextBox tb)
		{
			string language = GetSelectedLanguage();
			string value = GetAttributeValue(buttonElement, attributeName);

			if (value.StartsWith("$LocLabels:"))
			{
				string id = value.Replace("$LocLabels:", "");
				tb.Text = Helpers.GetLocLabelTextById(id, language);
				tb.ToolTip = id;
			}
			else
			{
				tb.Text = value;
			}
		}
		private void SaveLabel(TextBox tb, string[] attributes)
		{
			SaveLabel(tb, attributes, GetSelectedLanguage());
		}
		private void SaveLabel(TextBox tb, string[] attributes, string language)
		{
			string newText = tb.Text;
			if (newText.StartsWith("$Resources:") || newText.StartsWith("$Resources(EntityDisplayName):"))
			{
				foreach (string att in attributes)
				{
					_sourceElement.SetAttributeValue(att, newText);
				}
			}
			else
			{
				foreach (string att in attributes)
				{
					string id = GetAttributeValue(_sourceElement, att);
					if (id.StartsWith("$LocLabels:"))
					{
						id = id.Replace("$LocLabels:", "");
						SetLocLabelTextById(id, language, newText);
					}
					else
					{
						MessageBox.Show("Unable to set label for attribute " + att);
					}
				}
			}
		}
		/* 
		//modified to use Helpers.GetLocLabelTextById
		private string GetLocLabelTextById(string id, string language)
		{
			string text = string.Empty;
			XElement LocLabel = MainWindow.CurrentSolution.RibbonDiffXml.Descendants("LocLabel").Where(x => x.Attribute("Id").Value == id).FirstOrDefault();
			
			if (LocLabel != null)
			{
				XElement Title = LocLabel.Descendants("Title").Where(x => x.Attribute("languagecode").Value == language).FirstOrDefault();
				if (Title == null) Title = LocLabel.Descendants("Title").Where(x => x.Attribute("languagecode").Value == Connection.CurrentConnection.BaseLanguage).FirstOrDefault();

				if (Title != null)
				{
					text = Title.Attribute("description").Value;
				}
			}
			return text;
		}
		*/
		private void SetLocLabelTextById(string id, string language, string text)
		{
			XElement LocLabels = MainWindow.CurrentSolution.RibbonDiffXml.Descendants("LocLabels").FirstOrDefault();

			XElement LocLabel = LocLabels.Elements().Where(x => x.Attribute("Id").Value == id).FirstOrDefault();
			if (LocLabel == null)
			{
				//add new label if doesnt exist yet
				LocLabel = new XElement("LocLabel");
				LocLabel.SetAttributeValue("Id", id);
				LocLabels.Add(LocLabel);
				XElement newTitles = new XElement("Titles");
				LocLabel.Add(newTitles);
			}

			XElement Titles = LocLabel.Element("Titles");
			XElement Title = Titles.Elements().Where(x => x.Attribute("languagecode").Value == language).FirstOrDefault();
			if (Title == null)
			{
				//add title if doesnt exist yet.
				Title = new XElement("Title");
				Title.SetAttributeValue("languagecode", language);
				Titles.Add(Title);
			}

			string oldValue = GetAttributeValue(Title, "description");
			if (oldValue != text)
			{
				Title.SetAttributeValue("description", text);
				MainWindow.CurrentMainPage.RenderRibbon();
			}
		}

		#endregion

		#region Size

		private void LoadAvailableSizes()
		{
			try
			{
				//find the "maxsize" layout for the button's group.
				XElement Group = _sourceElement.Ancestors("Group").FirstOrDefault();
				string groupId = Group.Attribute("Id").Value;
				string templateName = Group.Attribute("Template").Value;
				XElement Scaling = Group.Ancestors("Tab").Elements("Scaling").FirstOrDefault();
				XElement MaxSize = Scaling.Elements("MaxSize").Where(x => x.Attribute("GroupId").Value == groupId).FirstOrDefault();
				string groupMaxSizeLayoutTitle = MaxSize.Attribute("Size").Value;
				XElement Templates = Group.Ancestors().Last().Descendants("Templates").FirstOrDefault();
				XElement GroupTemplate = Templates.Descendants("GroupTemplate").Where(x => x.Attribute("Id").Value == templateName).FirstOrDefault();
				XElement Layout = GroupTemplate.Elements("Layout").Where(x => x.Attribute("Title").Value == groupMaxSizeLayoutTitle).FirstOrDefault();

				//add each of the overflowsections to the sizepicker combobox
				List<string> sizes = new List<string>();
				foreach (XElement OverflowSection in Layout.Descendants("OverflowSection"))
				{
					XAttribute TemplateAlias = OverflowSection.Attribute("TemplateAlias");
					if (TemplateAlias != null && !sizes.Contains(TemplateAlias.Value))
					{
						sizes.Add(TemplateAlias.Value);

						ComboBoxItem i = new ComboBoxItem();
						i.Content = TemplateAlias.Value + "(" + OverflowSection.Attribute("DisplayMode").Value + ")";
						i.Tag = TemplateAlias.Value;
						SizePicker.Items.Add(i);
					}
				}
			}
			catch { }

			if (SizePicker.Items.Count == 0)
			{
				ComboBoxItem i = new ComboBoxItem();
				i.Content = "isv";
				i.Tag = "isv";
				SizePicker.Items.Add(i);
			}
		}

		void SizePicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			ComboBoxItem item = (ComboBoxItem)SizePicker.SelectedItem;
			if (item != null)
			{
				_sourceElement.SetAttributeValue("TemplateAlias", item.Tag.ToString());
				GetDiffButton().SetAttributeValue("TemplateAlias", item.Tag.ToString());
				MainWindow.CurrentMainPage.RenderRibbon();
			}
		}

		#endregion

		#region Position / Sequence

		private void PositionTextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			int num = 0;
			if (int.TryParse(PositionTextBox.Text, out num))
			{
				SetButtonSequence(_sourceElement, num);
			}
			else
			{
				PositionTextBox.Text = GetAttributeValue(_sourceElement, "Sequence");
			}
		}

		private void MoveLeft_Click(object sender, RoutedEventArgs e)
		{
			int currentSeq = int.Parse(_sourceElement.Attribute("Sequence").Value);
			List<int> otherSeq = new List<int>();
			foreach (XElement siblings in _sourceElement.Parent.Elements())
			{
				otherSeq.Add(int.Parse(siblings.Attribute("Sequence").Value));
			}
			otherSeq.Sort();

			//already at left
			if (otherSeq[0] == currentSeq)
			{
				return;
			}

			//moving to leftmost position
			if (otherSeq[1] == currentSeq)
			{
				SetButtonSequence(_sourceElement, otherSeq[0] - 10);
				return;
			}

			//moving between the button to the left and the button two to the left
			for (int i = 0; i < otherSeq.Count; i++)
			{
				if (otherSeq[i] == currentSeq)
				{
					int mid = (otherSeq[i - 1] + otherSeq[i - 2]) / 2;
					SetButtonSequence(_sourceElement, mid);
					return;
				}
			}
		}

		private void MoveRight_Click(object sender, RoutedEventArgs e)
		{
			int currentSeq = int.Parse(_sourceElement.Attribute("Sequence").Value);
			List<int> otherSeq = new List<int>();
			foreach (XElement siblings in _sourceElement.Parent.Elements())
			{
				otherSeq.Add(int.Parse(siblings.Attribute("Sequence").Value));
			}
			otherSeq.Sort();
			otherSeq.Reverse();

			//already at left
			if (otherSeq[0] == currentSeq)
			{
				return;
			}

			//moving to leftmost position
			if (otherSeq[1] == currentSeq)
			{
				SetButtonSequence(_sourceElement, otherSeq[0] + 10);
				return;
			}

			//moving between the button to the left and the button two to the left
			for (int i = 0; i < otherSeq.Count; i++)
			{
				if (otherSeq[i] == currentSeq)
				{
					int mid = (otherSeq[i - 1] + otherSeq[i - 2]) / 2;
					SetButtonSequence(_sourceElement, mid);
					return;
				}
			}
		}

		private void SetButtonSequence(XElement button, int newSequence)
		{
			if (newSequence < 0)
			{
				newSequence = 0;
			}

			string oldNum = GetAttributeValue(button, "Sequence");
			if (newSequence.ToString() != oldNum)
			{
				_sourceElement.SetAttributeValue("Sequence", newSequence.ToString());
				GetDiffButton().SetAttributeValue("Sequence", newSequence.ToString());

				//re-render current ribbon tab
				MainWindow.CurrentMainPage.RenderRibbon();
				this.PositionTextBox.Text = newSequence.ToString();
			}
		}

		#endregion

		#region Images

		private void Image16TextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			UpdateImage(Image16TextBox, "Image16by16");
		}

		private void Image32TextBox_LostFocus(object sender, RoutedEventArgs e)
		{
			UpdateImage(Image32TextBox, "Image32by32");
		}

		private void UpdateImage(AutoCompleteBox imageBox, string attributeName)
		{
			string old = GetAttributeValue(_sourceElement, attributeName);
			if (string.Compare(old, imageBox.Text, StringComparison.CurrentCulture) != 0)
			{
				_sourceElement.SetAttributeValue(attributeName, imageBox.Text);
				GetDiffButton().SetAttributeValue(attributeName, imageBox.Text);
				MainWindow.CurrentMainPage.RenderRibbon();
			}
		}

		#endregion

		
		//forwards an enter key press to a lostfocus event handler
		private void SetupEnterKeyHandler( Control c, Action<object,RoutedEventArgs> method )
		{
			c.KeyUp += (sender, e) =>
			{
				if (e.Key == Key.Enter)
				{
					method(c, e);
				}
			};
		}

		private XElement GetDiffButton()
		{
			string id = _sourceElement.Attribute("Id").Value;
			XElement CustomActions = MainWindow.CurrentSolution.RibbonDiffXml.Descendants("CustomActions").First();
			XElement Button = CustomActions.Descendants("Button").Where(x => x.Attribute("Id").Value == id).FirstOrDefault();
			return Button;
		}

		private string GetAttributeValue(XElement el, string atName)
		{
			XAttribute at = el.Attribute(atName);
			if (at != null)
			{
				return at.Value;
			}
			else
			{
				return string.Empty;
			}
		}

		private void ShowSectionsLinkButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			MainWindow.CurrentMainPage.ToggleSectionLines((TextBlock)sender);
		}

		private void ShowSectionsLinkButton_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Enter)
			{
				MainWindow.CurrentMainPage.ToggleSectionLines((TextBlock)sender);
			}
		}

		private void LanguageId_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (_isEditable && e.RemovedItems.Count > 0)
			{
				string previousLang = ((ComboBoxItem)e.RemovedItems[0]).Tag.ToString();
				SaveLabel(LabelTextBox, new string[] { "LabelText" }, previousLang);
				SaveLabel(ToolTipTitleTextBox, new string[] { "ToolTipTitle" }, previousLang);
				SaveLabel(TooltipDescriptionTextBox, new string[] { "ToolTipDescription" }, previousLang);
				Connection.CurrentConnection.LastLanguageUsed = GetSelectedLanguage();
			}
			LoadLabel(this._sourceElement, "LabelText", LabelTextBox);
			LoadLabel(this._sourceElement, "ToolTipTitle", ToolTipTitleTextBox);
			LoadLabel(this._sourceElement, "ToolTipDescription", TooltipDescriptionTextBox);
		}

		private void BrowseForImage16_Click(object sender, RoutedEventArgs e)
		{
			BrowseForImage(Image16TextBox, "Image16by16");
		}

		private void BrowseForImage32_Click(object sender, RoutedEventArgs e)
		{
			BrowseForImage(Image32TextBox, "Image32by32");
		}

		private void BrowseForImage(AutoCompleteBox acBox, string elementName)
		{
			string text = acBox.Text;
			if (String.IsNullOrWhiteSpace(text)) text = String.Empty;
			WebResourceDialog webResourceDialog = new WebResourceDialog(ResourceType.Image, text.Replace("$webresource:", ""));
			MainWindow.CurrentMainPage.ShowPopupDialog(webResourceDialog, (result) =>
			{
				if (result != null)
				{
					acBox.Text = "$webresource:" + result.ToString();
					UpdateImage(acBox, elementName);
				}
			});
		}
	}
}
